namespace SimpleWebServices.Data
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Web;
    using System.Xml.Serialization;
    using SimpleWebServices.Configuration;
    using SimpleWebServices.Web;

    public abstract class Record : ValueObject<Record>, IRecord
    {
        protected Record()
            : this(HttpCacheability.Server)
        {
        }

        protected Record(HttpCacheability cacheability)
        {
            this.RegisterProperty(x => x.Cacheability);
            this.RegisterProperty(x => x.Created);
            this.RegisterProperty(x => x.Etag);
            this.RegisterProperty(x => x.Expires);
            this.RegisterProperty(x => x.Modified);
            this.RegisterProperty(x => x.Status);
            this.RegisterProperty(x => x.Token);
            this.RegisterProperty(x => x.Urn);

            this.RegisterProperty(x => x.Entity);

            if (!this.Cacheability.HasValue)
            {
                this.Cacheability = cacheability;
            }

            if (!this.Status.HasValue)
            {
                this.Status = HttpStatusCode.OK;
            }
        }

        [XmlIgnore]
        public HttpCacheability? Cacheability
        {
            get;
            set;
        }

        [XmlIgnore]
        public DateTime? Created
        {
            get;
            set;
        }

        public abstract string Entity { get; }

        [XmlIgnore]
        public string Etag
        {
            get;
            set;
        }

        [XmlIgnore]
        public Expiration Expires
        {
            get;
            set;
        }

        [XmlIgnore]
        public DateTime? Modified
        {
            get;
            set;
        }

        [XmlIgnore]
        public HttpStatusCode? Status
        {
            get;
            set;
        }

        [XmlIgnore]
        public Token? Token
        {
            get;
            set;
        }

        [XmlIgnore]
        public virtual AbsoluteUri Urn
        {
            get;
            set;
        }

        public static bool Exists<T>(AbsoluteUri urn)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Exists(urn);
        }

        public static bool Exists<T>(string xpath)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Exists(xpath);
        }

        public static bool Exists<T>(Token token)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Exists(token);
        }

        public static bool Remove<T>(AbsoluteUri urn)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Delete(urn);
        }

        public static bool Remove<T>(Token token)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Delete(token);
        }

        public static T Retrieve<T>(AbsoluteUri urn)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Select<T>(urn);
        }

        public static T Retrieve<T>(Token token)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Select<T>(token);
        }

        public static IList<T> Search<T>(string xpath)
            where T : IRecord
        {
            return RepositoryConfiguration.Resolve<T>().Query<T>(xpath);
        }

        public virtual void Store<T>()
            where T : IRecord
        {
            this.Modified = DateTimeFactory.UtcNow;

            RepositoryConfiguration.Resolve<T>().Upsert(this);
        }
    }
}